<template>
  <div>
    <v-row v-if="!loading">
      <v-col style="margin-left: 20%;" >
        <v-btn
            icon
            color="#BEBEBE"
            @click="enlarge"
        >
          <v-icon>mdi-arrow-top-left-bottom-right</v-icon>
        </v-btn>
        <v-btn
            icon
            color="#BEBEBE"
            @click="reduce"
        >
          <v-icon>mdi-arrow-collapse</v-icon>
        </v-btn>
        <v-btn
            icon
            color="#BEBEBE"
            @click="resize"
        >
          <v-icon>mdi-autorenew</v-icon>
        </v-btn>
        <v-checkbox
            @click="click"
            v-model="autoResize"
            label="自动缩放"
        ></v-checkbox>
      </v-col>
    </v-row>
    <v-row ref="polar">
      <div id="polar"/>
    </v-row>
  </div>
</template>

<script>
import Plotly from 'plotly.js-dist'
import * as d3 from 'd3'
import _, { map } from 'underscore'
import {sliderBottom} from "d3-simple-slider"
import APIHelper, {stuName, color} from '../util/APIHelper'

const maxWidth = document.body.clientWidth;
const maxHeight = 1000;
const width = maxWidth * 0.58
const height = 700;

// console.log("color", color)
const angle = d3.scaleLinear()
    .domain([0, 360])
    .range([0, 2 * Math.PI]);

export default {
  name: "PolarCT",
  data() {
    return {
      loading: true,
      autoResize: false,
      refWidth: 0,
      radius : Math.min(width, height) / 2 - 100,
      svg : Object,
      processLen: 0,
      oriRadius: Math.min(width, height) / 2 - 100,
    }
  },
  computed: {
    stuStartIdx() {
      return this.$store.state.stuStartIdx
    },
    allLineX() {
      return this.$store.state.allLineX
    },
    allLineY() {
      return this.$store.state.allLineY
    },
    allLineZ() {
      return this.$store.state.allLineZ
    },
    points() {
      return this.$store.state.points
    },
    maxErr() {
      return this.$store.state.maxErr
    },
    errs() {
      return this.$store.state.errs
    },
    selectedList() {
      return this.$store.state.selectedList
    },
    stuList() {
      return this.$store.state.stuList
    },
    opt() {
      return this.$store.state.opt
    },
    preOpt() {
      return this.$store.state.preOpt
    },
    trajectoryColor() {
      return this.$store.state.trajectoryColor
    },
    trajectoryX() {
      return this.$store.state.trajectoryX
    },
    trajectoryY() {
      return this.$store.state.trajectoryY
    },
    trajectoryZ() {
      return this.$store.state.trajectoryZ
    },
    preColor() {
      return this.$store.state.preColor
    },
    trajectoryData() {
      const { points, maxErr, errs} = this
      return {
        points, maxErr, errs
      }
    }
  },
  watch :{
    trajectoryData() {
      this.processLen = this.errs.length
      this.drawCT()
    }
  },
  mounted() {
    let that = this

    that.refWidth= that.$refs.polar.offsetWidth;
    // console.log("refHeight", that.refWidth)

    that.svg = d3.select('#polar').append("svg")
        .attr("width", width)
        .attr("height", maxHeight)
        .append("g")
        .attr("transform", "translate(" + that.refWidth / 2 + "," + maxHeight / 3 + ")")
  },
  methods: {
    resizePolar(r){
      let that = this
      d3.selectAll(".zoom").remove()
      that.radius = r
      let p = that.points[that.opt].filter(function (val){
        return that.selectedList.hasOwnProperty(stuName[val[0]]) && that.selectedList[stuName[val[0]]].includes(val[1])
      })
      that.getAngleAxis()
      that.updateRadiusAxis(p, that.errs[that.opt])
      that.updatePos(p)
    },
    resize(){
      let that = this
      that.resizePolar(that.oriRadius)
    },
    reduce(){
      let that = this
      that.resizePolar(that.radius /= 1.2)

    },
    enlarge(){
      let that = this
      that.resizePolar(that.radius *= 1.2)
    },
    getAngleAxis() {
      // 角度坐标轴
      // this.svg.selectAll(".a").remove()
      var ga = this.svg.append("g")
          .attr("class", "a axis zoom")
          .selectAll("g")
          .data(d3.range(-90, 270, 45))
          .enter().append("g")
          .attr("transform", function(d) {
            return "rotate(" + d + ")";
         });

      ga.append("line")
          .attr("x2", this.radius);
    },
    getPos() {

      let that = this

      let points = this.points[this.opt]
      points = points.filter(function (val){
        return that.selectedList.hasOwnProperty(stuName[val[0]]) && that.selectedList[stuName[val[0] - 1]].includes(val[1])
      })

      var y = _.map(this.points[0], _.last);
      var max =  Math.max.apply(null, y);
      max = Math.ceil(max*10)/10;

      var r = d3.scaleLinear()
          .domain([0, that.maxErr])
          .range([0, that.radius]);

      if (that.autoResize && max > that.maxErr) {
        r = d3.scaleLinear()
            .domain([0, max])
            .range([0, that.radius]);
      }

      var color = d3.scaleOrdinal(d3.schemeAccent);

      // change points index
      var line = d3.lineRadial()
          .angle((d) => {
            return angle(d[2]);
          })
          .radius((d) => {
            return r(d[3]);
          });

      this.svg.selectAll("point")
          .data([1, 1, 0, 100000])
          .enter()
          .append("circle")
          .attr("class", "point zoom")
          // .attr("transform", function(d) {
          //   let coors = line([d]).slice(1).slice(0, -1);
          //   return "translate(" + coors + ")"
          // })
          .attr("data-legend",function(d, i) { return i})
          .attr("r", 4)
          .text('')
          .attr("fill",function(d,i){
            var c = d3.color("steelblue");
            c.opacity = 0;
            return c + ""
          });
    },
    getLegend(){
      let that = this

      let lengendW = width * 0.3

      let p = that.points[that.opt].filter(function (val){
        return that.selectedList.hasOwnProperty(stuName[val[0]]) && that.selectedList[stuName[val[0] - 1]].includes(val[1])
      })

      let legendArea = this.svg.append("g")
          .attr("transform", "translate(" + lengendW + ",-600)");

      let legend = legendArea
          .attr("class", "point").selectAll("g")
          .data(p)
          .enter()
          .append("g")
          .attr("class", "legend")
          .attr("transform", function (d, i) {
            return "translate(0," + i * 30 + ")";
          });
      legend.append("rect")
          .attr("width", 20)
          .attr("height", 20)
          .style("fill", function (d, i) {
            return color[that.stuStartIdx[stuName[d[0]]] + d[1] - 1];
          });

      legend.append("text")
          .attr("x", 24)
          .attr("y", 9)
          .style("fill", function (d, i) {
            return color[i]
          })
          .attr("dy", ".35em")
          .text(function (d, i) {
            return stuName[d[0]] + '-' + d[1];
          });
    },
    updateLegend(points){
      let that = this
      let lengendW = width * 0.3

      let update = that.svg.selectAll(".legend").data(points)
      let enter = update.enter();
      let exit = update.exit()
      exit.remove()

      that.svg.selectAll('.legend_text').remove()

      let legend_update = update
          .attr("transform", function (d, i) {
            return "translate("+ lengendW +"," + (i * 30 - 200) + ")";
          })

      legend_update.append("rect")
          .attr("class", "legend_rect")
          .attr("width", 20)
          .attr("height", 20)
          .style("fill", function (d, i) {
            return color[that.stuStartIdx[stuName[d[0]]] + d[1] - 1];
          })

      legend_update.append("text")
          .attr("class", "legend_text")
          .attr("x", 24)
          .attr("y", 9)
          .style("fill", function (d, i) {
            return color[that.stuStartIdx[stuName[d[0]]] + d[1] - 1];
          })
          .attr("dy", ".35em")
          .text(function (d, i) {
            return stuName[d[0]] + '-' + d[1];
          });

      let legend_enter = enter.append("g")
          .attr("class", "legend")
          .attr("transform", function (d, i) {
            return "translate("+ lengendW +"," + (i * 30 - 200) + ")";
          })

      legend_enter
          .append("rect")
          .attr("class", "legend_rect")
          .attr("width", 20)
          .attr("height", 20)
          .style("fill", function (d, i) {
            return color[that.stuStartIdx[stuName[d[0]]] + d[1] - 1];
          })

      legend_enter
          .append("text")
          .attr("class", "legend_text")
          .attr("x", 24)
          .attr("y", 9)
          .style("fill", function (d, i) {
            return color[that.stuStartIdx[stuName[d[0]]] + d[1] - 1];
          })
          .attr("dy", ".35em")
          .text(function (d, i) {
            return stuName[d[0]] + '-' + d[1];
          });
    },
    updatePos(points){
      let that = this

      let y = _.map(points, _.last);
      let max =  Math.max.apply(null, y);
      max = Math.ceil(max*10)/10;

      let r = d3.scaleLinear()
          .domain([0, that.maxErr])
          .range([0, that.radius]);

      if (that.autoResize && max > that.maxErr) {
        r = d3.scaleLinear()
            .domain([0, max])
            .range([0, that.radius]);
      }



      // change points index
      let line = d3.lineRadial()
          .angle((d) => {
            return angle(d[2]);
          })
          .radius((d) => {
            return r(d[3]);
          });
      let update = that.svg.selectAll(".point").data(points)
      let enter = update.enter();
      let exit = update.exit()
      exit.remove()

      update.attr("class", "point zoom")
          .attr("transform", function(d) {
            let coors = line([d]).slice(1).slice(0, -1);
            return "translate(" + coors + ")"
          })
          .attr("r", 4)
          .attr("fill",function(d,i){
            return color[that.stuStartIdx[stuName[d[0]]] + d[1] - 1];
          });

      enter.append("circle")
          .attr("class", "point zoom")
          .attr("transform", function(d) {
            let coors = line([d]).slice(1).slice(0, -1);
            return "translate(" + coors + ")"
          })
          .attr("data-legend",function(d, i) { return i})
          .attr("r", 4)
          .attr("fill",function(d,i){
            return color[that.stuStartIdx[stuName[d[0]]] + d[1] - 1];
          });

    },
    updateRadiusAxis(points, err){
      let that = this
      let y = _.map(points, _.last);
      let max =  Math.max.apply(null, y);
      max = Math.ceil(max*10)/10;

      err = parseFloat(err).toFixed(2)

      let r = d3.scaleLinear()
          .domain([0, err])
          .range([0, that.radius * err / that.maxErr]);

      if (that.autoResize && max > that.maxErr) {
        r = d3.scaleLinear()
            .domain([0, err])
            .range([0, that.radius * err / max]);
      }

      that.svg.selectAll(".r").remove()

      let rNum = err < 300 ? 3 : err > 750 ? 10 : 5

      if(that.radius / that.oriRadius > 2){
        rNum *= Math.floor(that.radius / that.oriRadius * 0.9)
      }
      else if(that.radius / that.oriRadius < 0.5){
        rNum = Math.ceil(rNum * that.radius / that.oriRadius)
      }

      let gr = that.svg.append("g")
          .attr("class", "r axis zoom")
          .selectAll("g")
          .data(r.ticks(rNum).slice(1, -1))
          .enter().append("g");

      // gr.selectAll(".errCircle").remove()
      that.svg.append("g")
          .attr("class", "r errCircle zoom")
          .append("circle")
          .attr("r", r(err))
          .style("stroke-dasharray", "5 5")
          .style("stroke-width", 1)
          .style("stroke", '#EE7785')
          .style("fill", "#FADAD8")
          .style("fill-opacity", 0.2)

      that.svg.append("g")
          .attr("class", "r errText zoom")
          .append("text")
          .attr("y", -r(err) - 4)
          .attr("transform", "rotate(20)")
          .style("text-anchor", "middle")
          .style("fill","#E71D36")
          .text(err+'m');


      // gr.selectAll(".RadiusCircle").remove()
      gr.append("circle")
          .attr("class", "RadiusCircle zoom")
          .attr("r", r)
          .style("stroke-dasharray", "5 5");

      // gr.selectAll("text").remove()
      gr.append("text")
          .attr("y", function(d) { return -r(d) - 4; })
          .attr("transform", "rotate(20)")
          .style("text-anchor", "middle")
          .text(function(d) { return d; });

      // console.log(gr)


    },
    getBarSlider(){
      let that = this
      let barWidth = that.refWidth*0.8
      let barHeight = 20
      // let transW = -300
      let transW = - that.refWidth / 2.5
      let transH = 550

      let errsIdx = that.errs.map((d, i) => ({
        errId: i,
        value: d,
      }));


      let padding = 0.1;

      let xBand = d3
          .scaleBand()
          .domain((function() {
            let t = [];
            for (let i = 0; i < errsIdx.length; i++) {
              t.push(i);
            }
            return t;
          })())
          .range([0, barWidth])
          .padding(padding);

      let xLinear = d3
          .scaleLinear()
          .domain([
            1,
            errsIdx.length,
          ])
          .range([
            xBand.bandwidth() / 2 + xBand.step() * padding - 0.5,
            barWidth - xBand.bandwidth() / 2 - xBand.step() * padding - 0.5
          ]);

      let y = d3
          .scaleLinear()
          .domain([0, d3.max(errsIdx, d=>d.value)])
          .nice()
          .range([barHeight, 0]);

      let slider = g =>
          g.attr('transform', `translate(${transW},${transH})`).call(
              sliderBottom(xLinear)
                  .step(1)
                  .ticks(errsIdx.length / 20)
                  .default(1)
                  .on('onchange', errId => {
                    draw(errId)
                    that.$store.commit('setOpt', errId - 1)

                    let updateAnnotations = [{
                          x: that.allLineX[0][0][that.opt],
                          y: that.allLineY[0][0][that.opt],
                          z: that.allLineZ[0][0][that.opt],
                          xref: 'x',
                          yref: 'y',
                          zref: 'z',
                          text: '当前位置',
                          showarrow: true,
                          arrowhead: 3,
                          ax: 20,
                          ay: 20,
                          az: 20
                        }]
                    Plotly.relayout('myDiv', 'scene.annotations', updateAnnotations)
                    let p = that.points[that.opt].filter(function (val){
                      return that.selectedList.hasOwnProperty(stuName[val[0]]) && that.selectedList[stuName[val[0]]].includes(val[1])
                    })
                    // that.getAngleAxis()
                    that.updateRadiusAxis(p, that.errs[that.opt])
                    that.updatePos(p)
                  })
          );


      let bars = that.svg
          .append('g')
          .attr('transform', `translate(${transW},${transH - 55})`)
          .selectAll('rect')
          .data(errsIdx);

      let barsEnter = bars
          .enter()
          .append('rect')
          .attr('x', d => xBand(d.errId))
          .attr('y', d => {
            return y(d.value)
          })
          .attr('height', d => y(0) - y(d.value))
          .attr('width', xBand.bandwidth());

      that.svg.append('g').call(slider);

      let draw = selected => {
        barsEnter
            .merge(bars)
            .attr('fill', d => (d.errId === selected - 1 ? '#bad80a' : '#e0e0e0'));
      };

      draw(1);
    },
    drawCT() {
      this.getAngleAxis()
      // this.getRadiusAxis()
      this.updateRadiusAxis(this.points[0], this.errs[0])
      this.getPos()
      this.getLegend()
      // this.getAngleAxis()
      // this.getSlider()
      this.getBarSlider()
      this.loading = false
    },
    updateCT() {
      let that = this
      let p = that.points[that.opt].filter(function (val){
        return that.selectedList.hasOwnProperty(stuName[val[0]]) && that.selectedList[stuName[val[0]]].includes(val[1])
      })
      that.updatePos(p)
      that.updateLegend(p)
    },
    test(){
      alert('test')
    },
    click(){
      let that = this
      let p = that.points[that.opt].filter(function (val){
        return that.selectedList.hasOwnProperty(stuName[val[0]]) && that.selectedList[stuName[val[0]]].includes(val[1])
      })
      // that.getAngleAxis()
      that.updateRadiusAxis(p, that.errs[that.opt])
      that.updatePos(p)
    }
  }
}
</script>

<style>
.frame {
  fill: none;
  stroke: #000;
}

.axis text {
  font: 10px sans-serif;
}

.axis line,
.axis circle {
  fill: none;
  stroke: steelblue;
  stroke-dasharray: 4;
}

.axis:last-of-type circle {
  stroke: steelblue;
  stroke-dasharray: none;
}

.line {
  fill: none;
  stroke: orange;
  stroke-width: 3px;
}
</style>